#pragma once

#include <fstream>
#include <string>
#include <map>
#include <vector>

#include <vbl/img/ImageDefs.h>
#include <vbl/img/ImageAdaptorImage.h>
#include <vbl/Exception.h>
#include <vbl/util/Array2D.h>
#include <vbl/util/StringUtils.h>
#include <vbl/util/FileUtils.h>
#include <vbl/calib/BogUtils.h>
#include <vbl/img/proc/ImageUndistort.h>
#include <vbl/img/stat/Histogram.h>
#include <vbl/img/ImageCopy.h>
#include <vbl/img/io/ImageIO.h>
#include <vbl/img/proc/Demosaic.h>
#include <vbl/img/ImageTransform.h>
#include <vbl/util/window.h>

#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>

using namespace std;
using namespace boost;
using namespace vbl;

#define USE_CAS_DATASET
#define USE_OLD_DAT_NOTATION
#define USE_OLD_FILESYSTEM

typedef pair<vector<util::Array2D<double>>,vector<util::Array2D<double>>> dist_map_t;
typedef vbl::img::stat::Histogram< 3, vbl::img::ImageRGB::value_type, 20, double > AppearanceHist; // TODO should be CIE-LAB

using namespace vbl;

struct rectangle 
{
	bool isVisible;
	int xmin;
	int xmax;
	int ymin;
	int ymax;
};

class ProgramOptions
{
private:
	void computeCameraParameters();

	void getFilesPerCamera( vector<vector<string>> & files );

	void getFilesPerCamera_old( vector<vector<string>> & files );

	void readConfigFile(string config_file_path, string & scenario_name, string & proba_path, string & image_path, 
					string & background_path, string & pom_file, string & output_path, string & bog_path, int & pom_x, 
					int & pom_y, int & begin_frame, int & num_of_frames, int & batch_size, double & passProb);

	void getImagePaths( vector<vector<string>> & filesPerCamera );

	void computeUndistortMap( const calib::BogData& bogData, util::Array2D<double> & mapXMat, util::Array2D<double> & mapYMat	);

	void readBogData( const string& bogDir,	calib::BogData* bogData	);

	void readPomFile();
	
	void computeOcclusionMap();

	void parseLine( string line );

	int calcOverlap( rectangle curr, rectangle comp );
	
	//template <typename T, template <class> class AP1, template <class> class AP2>
	void undistortImage( const img::ImageRGB & capuredImage, img::ImageRGB & undistortedImage, 
									const util::Array2D<double> & mapXMat, const util::Array2D<double> & mapYMat );

	void getAppearance( int frame, int location, vector<img::ImageRGB> & ims, vector<AppearanceHist> & appearance,
								   vector<bool> & visibility );

	void getImages( int frame, vector<img::ImageRGB> & ims_out );

	void getAppearance( int frame, rectangle r, img::ImageRGB & im, img::ImageRGB & background, AppearanceHist & apHist );

	void setupTemplates();

public:
	string scenario_name, proba_path, image_path, background_path, pom_file, output_path, bog_path;
	int pom_x, pom_y, begin_frame, num_of_frames, batch_size, pom_size, num_of_batches, max_detections, vsource, num_of_cams,
		total_locations, image_width, image_height;
	double pass_prob;
	vector<double> rot;
	bool b_save_images, use_appearance, use_appearance_shitrit, first_graph;
	vector<vector<rectangle>> pom_locations; // pom_locations[ cam ][ location ]
	vector<vector<string>> files_per_camera; // files_per_camera[ cam ][ file string ]
	dist_map_t dist_map;
	vector<vector<AppearanceHist>> templates; // templates[ template ][ cam ]
	vector<vector<bool>> camera_visibility; // camera_visibility[ template ][ cam ]
	vector<map<int,vector<int>>> occlusion_map; // occlusion_map[ cam ][ location ]
	vector<vector<double>> probabilities; // probabilites[ cam ][ location ]

	ProgramOptions( string config_file_path );

	//template <typename T, template <class> class AP1>
	void undistortImage( img::ImageRGB & capuredImage, const util::Array2D< double >& mapXMat, 
									const util::Array2D< double >& mapYMat );

	int calculateSurface( rectangle r );
};